package com.xinkao.log.rabbitmq;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.xinkao.log.config.system.TopicMqConfig;
import com.xinkao.log.datasource.DBIdentifier;
import com.xinkao.log.entity.EntryRules;
import com.xinkao.log.entity.Log;
import com.xinkao.log.mapper.DynamicDataMapper;
import com.xinkao.log.service.EntryRulesService;
import com.xinkao.log.service.LogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;
import org.springframework.amqp.core.Message;
import com.rabbitmq.client.Channel;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author 周洋
 * @Description 抽离日志系统为一个消费者
 * @createTime 2021/9/26 16:55
 */
@Slf4j
@Component
@RabbitListener(queues = TopicMqConfig.OPERATE_LOG_QUEUE_NAME)
public class ConsumersLogListener {

    @Autowired
    private LogService logService;

    @Autowired
    private EntryRulesService entryRulesService;

    @Resource
    private DynamicDataMapper dynamicDataMapper;

    @RabbitHandler
    public void process(JSONObject logObject,Channel channel, Message message) throws IOException {
        try {
            /**
             * 确认一条消息：<br>
             * channel.basicAck(deliveryTag, false); <br>
             * deliveryTag:该消息的index <br>
             * multiple：是否批量.true:将一次性ack所有小于deliveryTag的消息 <br>
             */
            Log log = JSON.toJavaObject(logObject, Log.class);
            //动态数据库连接
            DBIdentifier.setDbIp(logObject.getString("dbIp"));
            DBIdentifier.setDbName(logObject.getString("dbName"));
            DBIdentifier.setUsername(logObject.getString("username"));
            DBIdentifier.setPassword(logObject.getString("password"));

            //根据入参规则对内容进行处理转化
            String content = log.getContent();
            LinkedHashMap<String, Object> contentMap = JSON.parseObject(content,LinkedHashMap.class, Feature.OrderedField);
            //根据系统标识、模块名称查询入参规则
            //查询条件
            Query query  = new Query();
            Criteria criteria = Criteria.where("systemMark").is(log.getSystemMark()).and("module").is(log.getOperateModule());
            query.addCriteria(criteria);
            EntryRules entryRules = entryRulesService.findOne(query);
            String contentConversion = entryRules.getContentConversion();
            LinkedHashMap<String, Object> entryRulesMap = JSON.parseObject(contentConversion,LinkedHashMap.class, Feature.OrderedField);
            log.setContent(contentConversion(contentMap, entryRulesMap));

            //将日志信息进行持久化操作-MongoDB
            logService.save(log);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            /**
             * 消费者处理出了问题，需要告诉队列信息消费失败
             * 拒绝确认消息:<br>
             * channel.basicNack(long deliveryTag, boolean multiple, boolean requeue) ; <br>
             * deliveryTag:该消息的index<br>
             * multiple：是否批量.true:将一次性拒绝所有小于deliveryTag的消息。<br>
             * requeue：被拒绝的是否重新入队列 <br>
             */
            channel.basicNack(message.getMessageProperties().getDeliveryTag(),
                    false, true);
        }
    }

    /**
     * 根据入参规则对内容进行处理转化
     * @param contentMap
     * @param entryRulesMap
     * @return
     */
    private String contentConversion(LinkedHashMap<String, Object> contentMap, LinkedHashMap<String, Object> entryRulesMap) {
        StringBuilder requestBodyBuilder = new StringBuilder();
        for (Map.Entry entry : contentMap.entrySet()) {
            if(entryRulesMap.containsKey(entry.getKey().toString()) && !StrUtil.isEmptyIfStr(entry.getValue())){
                //如果当前value值为JSONObject,递归转换，并增加相应格式
                if(entry.getValue() instanceof JSONObject){
                    LinkedHashMap<String, Object> recursionContentMap = JSON.parseObject(entry.getValue().toString(),LinkedHashMap.class, Feature.OrderedField);
                    requestBodyBuilder.append("{");
                    requestBodyBuilder.append(contentConversion(recursionContentMap,entryRulesMap));
                    requestBodyBuilder.append("}，");
                }else if(entry.getValue() instanceof JSONArray){
                    //如果当前value值为JSONArray,循环为JSONObject再递归转换，并增加相应格式
                    JSONArray jsonArray = (JSONArray) entry.getValue();
                    requestBodyBuilder.append(entryRulesMap.get(entry.getKey().toString())+"：[");
                    for(Object object : jsonArray){
                        LinkedHashMap<String, Object> recursionContentMap = JSON.parseObject(object.toString(),LinkedHashMap.class, Feature.OrderedField);
                        requestBodyBuilder.append("{");
                        requestBodyBuilder.append(contentConversion(recursionContentMap,entryRulesMap));
                        requestBodyBuilder.append("}，");
                    }
                    if(requestBodyBuilder.length()>1){
                        requestBodyBuilder.deleteCharAt(requestBodyBuilder.length() -1);
                    }
                    requestBodyBuilder.append("]，");
                }else {
                    String name = getIdName(entry, entryRulesMap);
                    if(!StrUtil.isEmptyIfStr(name)){
                        requestBodyBuilder.append(name);
                    }
                    requestBodyBuilder.append(entryRulesMap.get(entry.getKey().toString())+"："+entry.getValue()+"，");
                }
            }
        }
        if(requestBodyBuilder.length()>1){
            requestBodyBuilder.deleteCharAt(requestBodyBuilder.length() -1);
        }
        return requestBodyBuilder.toString();
    }

    /**
     * 存在id类字段，查询相应name
     * @param entry
     * @param entryRulesMap
     * @return
     */
    private String getIdName(Map.Entry entry, LinkedHashMap<String, Object> entryRulesMap) {
        String str = "";
        if(entry.getKey().toString().toLowerCase().contains("id".toLowerCase())){
            //根据字段名称、表名查询相应动态库中的数据
            JSONObject jsonObject = new JSONObject();
            String[] s = entry.getKey().toString().split("I");
            if(s.length>0){
                String tableName = s[0];
                String name = tableName+"Name";
                String field = tableName+"_id as "+tableName+"Id ,"+tableName+"_name as "+tableName+"Name ";
                jsonObject.put("field",field);
                jsonObject.put("tableName",tableName);
                jsonObject.put("condition","delete_status = 0 and "+tableName+"_id = '"+entry.getValue()+"'");
                try {
                    JSONObject dynamicData = dynamicDataMapper.getDynamicData(jsonObject);
                    if(!StrUtil.isEmptyIfStr(dynamicData)){
                        str =  entryRulesMap.get(name)+"："+dynamicData.getString(name)+"，";
                    }
                }catch (Exception e){
                    str =  "";
                }
            }
        }
        return str;
    }
}
